#!/bin/bash
#
# Copyright (C) 2011-2020 Aratelia Limited - Juan A. Rubio and contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

#
# Travis-ci build script
#

# Globals
WORKING_DIR="$HOME/tizonia-openmax-il" # Default value for working directory
INSTALL_DIR="$HOME/build" # Default value for install directory
TIZRMD_PID=-1

if [ "$2" != "" ]; then
    WORKING_DIR="$2"
fi

if [ "$3" != "" ]; then
    INSTALL_DIR="$3"
fi

# Constants
readonly E_BADARGS=85
readonly E_NOFILE=86
readonly E_BAD_CLONE=87
readonly CWD=$(pwd)

readonly TIZONIA_CONF_PATH="$HOME/.config/tizonia/tizonia.conf"

readonly SKEMA_GIT_REPO=https://github.com/tizonia/skema
readonly SKEMA_DIR="$INSTALL_DIR"/skema
readonly SKEMA_BIN_DIR="$SKEMA_DIR"/bin

# A list of skema test suites that should not be executed
declare -ar SKEMA_EXEMPT_SUITES=( \
    "Mp3Streaming" \
    "VorbisDecodeBaseProfile" \
    "AacPlayback" \
    "Mp3StreamingClient" \
    "Mp3StreamingClientPortAutoDetect" \
    "OpusPlayback" \
    "PcmPlaybackPulse" \
    "WavPlayback" \
    "Vp8Playback" \
    "WebmVp8Playback" \
)

#
# Pre-requisites
#

# Create directories
if [ ! -d "$INSTALL_DIR" ]; then
    echo "Creating the install directory: $INSTALL_DIR"
    mkdir -p "$INSTALL_DIR"
fi

echo "Changing dir to working directory: $WORKING_DIR"
cd "$WORKING_DIR"

# Export important variables
LIB_DIR="$INSTALL_DIR"/lib
PKG_CONFIG_DIR="$LIB_DIR"/pkgconfig
export PKG_CONFIG_PATH="$PKG_CONFIG_DIR"
export LD_LIBRARY_PATH="$LIB_DIR"

##################################################################
# Simple function to print a debug/error message with some extra info
#
# Globals
#   WORKING_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function err {
  echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $@" >&2
}

##################################################################
# Simple function to go to the working directory
#
# Globals
#   WORKING_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function cd_to_working_dir {
    echo "Changing dir to working directory: $WORKING_DIR"
    cd "$WORKING_DIR"
}

##################################################################
# Simple function to check if a string exists in an array
#
# Globals
#   none
# Arguments:
#   The search string is the first argument
#   The array is the second argument
# Returns:
#   0 if success, 1 on error
##################################################################
function exists_in_array {
    local e
    for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
    return 1
}

##################################################################
# Run all the installed skema suites
#
# Globals
#   None
# Arguments:
#   None
# Returns:
#   None
##################################################################
function start_dbus {
    # Only start D-BUS and the RM daemon if RM is enabled in tizonia.conf
    local rm_needed=$(sed -rn 's/^enabled(\s*)=(\s*)(true|false)/\3/p' "$TIZONIA_CONF_PATH")
    if [[ "$rm_needed" == "true" ]]; then
        ## test for an existing bus daemon, just to be safe
        if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then
            ## if not found, launch a new one
            export $(dbus-launch --exit-with-session)
            echo "D-Bus per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS"
            echo "D-Bus per-session daemon PID is    : $DBUS_SESSION_BUS_PID"
        fi

        "$INSTALL_DIR"/bin/tizrmd &
        TIZRMD_PID=$(pidof tizrmd)
        if [[ -z "$TIZRMD_PID" ]] ; then
            err "Unable to start the resource manager deamon"
            exit 1
        fi
        echo "Tizonia RM daemon instantiated: pid $ltrmdpid."
    fi
}

##################################################################
# Installs the binary dependencies
#
# Globals
#   None
# Arguments:
#   None
# Returns:
#   None
##################################################################
function install_deps {
    echo "Installing debian dependencies..."
    sudo apt-get update -qq && sudo apt-get install -qq \
        build-essential autoconf autoconf-archive  \
        automake autotools-dev libtool libmad0-dev liblog4c-dev \
        libasound2-dev libdbus-1-dev libsqlite3-dev \
        uuid-dev libsdl1.2-dev libvpx-dev libmp3lame-dev libfaad-dev \
        libev-dev libtag1-dev libfishsound-dev libmediainfo-dev \
        libcurl3-dev libpulse-dev libsndfile1-dev libatomic-ops-dev \
        python-dev python-pip curl check wget sqlite3 dbus-x11 &>/dev/null \
        && sudo apt-get remove --purge $(dpkg -l | grep libboost | awk '{print $2}') \
        && sudo add-apt-repository -y ppa:boost-latest/ppa \
        && sudo apt-get update -qq \
        && sudo apt-get install -qq libboost1.54-all-dev
    return $?
}

##################################################################
# Installs python modules
#
# Globals
#   WORKING_DIR
#   INSTALL_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function install_python_deps {
    cd_to_working_dir

    echo "Installing pip and an older version of the gmusicapi python module..."
    wget https://bootstrap.pypa.io/get-pip.py \
        && sudo python get-pip.py \
        && sudo pip install gmusicapi --upgrade

    echo "Now installing the latest gmusicapi from source..."
    git clone https://github.com/simon-weber/gmusicapi \
        && cd gmusicapi \
        && sudo python setup.py install

    if [[ "$exit_status" -ne 0 ]] ; then
        echo "Error while installing gmusicapi" >&2
    fi

    if [[ "$exit_status" -eq 0 ]] ; then
        sudo pip install soundcloud
        exit_status=$?
        if [[ "$exit_status" -ne 0 ]] ; then
            echo "Error while installing soundcloud" >&2
        fi
    fi

    return $exit_status
}

##################################################################
# Installs the source-based dependencies
#
# Globals
#   WORKING_DIR
#   INSTALL_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function install_src_deps {
    cd_to_working_dir

    echo "Installing source-based project dependencies..."
    local repos=( \
        https://git.xiph.org/mirrors/ogg.git \
        https://git.xiph.org/liboggz.git \
        https://git.xiph.org/opus.git \
        https://git.xiph.org/opusfile.git \
        https://git.xiph.org/flac.git )
    local folders=( ogg liboggz opus opusfile flac )
    local total=${#repos[*]}
    local exit_status=$?
    for (( i=0; i<=$(( total -1 )); i++ ))
    do
        cd "$WORKING_DIR" \
            && git clone ${repos[$i]} &>/dev/null \
            && cd ${folders[$i]} &>/dev/null ; \
            ./autogen.sh &>/dev/null ; \
            ./configure --prefix="$INSTALL_DIR" &>/dev/null ; \
            make -s -j8 V=0 install &>/dev/null
        exit_status=$?
        if [[ "$exit_status" -ne 0 ]] ; then
            echo "Error while building ${repos[$i]}" >&2
            exit_status=0
            #break
        fi
    done
    if [[ "$exit_status" -eq 0 ]] ; then
        cd "$WORKING_DIR"
        # Build libmpg123 1.19 from source
        wget http://www.juanrubio.me/tizonia/mpg123-1.16.0.tgz \
            && tar zxvf mpg123-1.16.0.tgz &>/dev/null \
            && cd mpg123-1.16.0 \
            && ./configure --prefix="$INSTALL_DIR" &>/dev/null \
            && make -s -j8 V=0 install &>/dev/null
        exit_status=$?
        if [[ "$exit_status" -ne 0 ]] ; then
            echo "Error while building mpg123" >&2
        fi
    fi
    if [[ "$exit_status" -eq 0 ]] ; then
        cd "$WORKING_DIR"
        # Install libspotify 12.1.51 binaries
        wget http://www.juanrubio.me/tizonia/libspotify-12.1.51-Linux-x86_64.tgz \
            && tar zxvf libspotify-12.1.51-Linux-x86_64.tgz &>/dev/null \
            && cd libspotify-12.1.51-Linux-x86_64 \
            && make install prefix="$INSTALL_DIR" &>/dev/null
        exit_status=$?
        if [[ "$exit_status" -ne 0 ]] ; then
            echo "Error while installing libspotify" >&2
        fi
    fi
    return "$exit_status"
}

##################################################################
# Installs the config files
#
# Globals
#   INSTALL_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function copy_config_files {
    cd_to_working_dir
    echo "Copy the Resource Manager's D-bus service file " \
         "to the user's local D-Bus search path"
    echo "${INSTALL_DIR}"
    local DBUS_SERVICE_FILE=${INSTALL_DIR}"/share/dbus-1/services/com.aratelia.tiz.rm.service"
    local DBUS_DIR="$HOME/.local/share/dbus-1/services"
    mkdir -p "$DBUS_DIR" && cp "$DBUS_SERVICE_FILE" "$DBUS_DIR"
    local exit_status=$?
    if [[ "$exit_status" -eq 0 ]] ; then
        echo "Preparing the $TIZONIA_CONF_PATH config file..."
        mkdir -p "$HOME/.config/tizonia" \
            && cp "$WORKING_DIR/config/src/tizonia.conf" "$TIZONIA_CONF_PATH"
        exit_status=$?
    fi

    # Modify tizonia config to make the ALSA renderer use the null pcm
    if [[ "$exit_status" -eq 0 ]] ; then
        echo "Preparing the $TIZONIA_CONF_PATH config file..."
        perl -pi -e 's/^(OMX\..*alsa_device.*)\bdefault\b/\1null/' "$TIZONIA_CONF_PATH"
        exit_status=$?
    fi
    return "$exit_status"
}

##################################################################
# Tizonia build
#
# Globals
#   INSTALL_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function build_tizonia {
    # Install MediaInfo dependencies
    sudo apt-get install -qq zlib1g-dev libzen-dev

    # Build MediaInfo 0.7.67 from source
    echo "Building MediaInfo 0.7.67 from source..."
    cd "$WORKING_DIR"
    wget http://juanrubio.me/tizonia/libmediainfo_0.7.67.orig.tar.gz \
        && tar zxvf libmediainfo_0.7.67.orig.tar.gz &>/dev/null \
        && cd MediaInfoLib/Project/GNU/Library \
        && ./autogen &>/dev/null \
        && ./configure --enable-shared --prefix="$INSTALL_DIR" \
        && make -s -j8 V=0 install
    local exit_status=$?

    # Build the tizonia player
    if [[ "$exit_status" -eq 0 ]] ; then
        cd "$WORKING_DIR" && cd player
        echo "Reconfiguring tizonia player for [DEBUG] build - Install dir [$INSTALL_DIR]..."
        autoreconf -ifs
        exit_status=$?
        if [[ "$exit_status" -eq 0 ]] ; then
            ./configure --prefix="$INSTALL_DIR" CFLAGS="-ggdb -Wall" \
                && make -s -j8 V=0 \
                && make -j8 install
            exit_status=$?
        fi
    fi

    return "$exit_status"
}

##################################################################
# Debug build
#
# Globals
#   INSTALL_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function build_debug {
    cd_to_working_dir
    echo "Reconfiguring Tizonia for [DEBUG] build - Install dir [$INSTALL_DIR]..."
    autoreconf -ifs
    local exit_status=$?
    if [[ "$exit_status" -eq 0 ]] ; then
        ./configure --prefix="$INSTALL_DIR" CFLAGS="-ggdb -Wall"
        exit_status=$?
    fi
    return "$exit_status"
}

##################################################################
# Release build
#
# Globals
#   INSTALL_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function build_release {
    cd_to_working_dir
    echo "Reconfiguring Tizonia for [RELEASE] build - Install dir [$INSTALL_DIR]..."
    autoreconf -ifs
    local exit_status=$?
    if [ $exit_status -eq 0 ] ; then
        ./configure --prefix="$INSTALL_DIR" CFLAGS="-O3 -DNDEBUG"
        exit_status=$?
    fi
    return "$exit_status"
}

##################################################################
# Conformance testing build
#
# Globals
#   INSTALL_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function build_conformace {
    cd_to_working_dir
    echo "Reconfiguring Tizonia for [CONFORMANCE TESTING] build - Install dir [$INSTALL_DIR]..."
    autoreconf -ifs
    local exit_status=$?
    if [[ "$exit_status" -eq 0 ]] ; then
        ./configure \
            --enable-silent-rules \
            --enable-blocking-etb-ftb \
            --prefix="$INSTALL_DIR" \
            CFLAGS="-ggdb -Wall"
        exit_status=$?
    fi
    return "$exit_status"
}

##################################################################
# Clones skema's git repo and installs all skema tags and suites
#
# Globals
#   None
# Arguments:
#   None
# Returns:
#   None
##################################################################
function install_skema {

    cd_to_working_dir

    # Step #1 : Clone repo
    echo "Cloning skema's repo..."
    git clone "$SKEMA_GIT_REPO" "$SKEMA_DIR" &>/dev/null
    local exit_status=$?
    if [[ "$exit_status" -ne 0 ]]; then
        err "Unable to clone skema's repo: $SKEMA_GIT_REPO"
        exit "${E_BAD_CLONE}"
    fi

    # Step #2: Install skema's tags
    cd "$SKEMA_BIN_DIR"

    local tags=( $(./skema list_tags) )
    local tag_count="${#tags[@]}"
    echo "Installing all $tag_count tags..."
    for t in "${tags[@]}"; do
        echo "Installing [$t]"
        ./skema uninstall_tag "$t"
        ./skema install_tag "$t"
    done

    # This is to verify that the tags are installed
    local installed_tags=( $(./skema list_installed_tags) )
    local installed_tag_count="${#installed_tags[@]}"
    if [[ "$installed_tag_count" -ne "$tag_count" ]]; then
        err "Error while installing tags"
        exit 1
    fi

    # Step #3: Install skema's test suites
    echo
    local suites=( $(./skema list_suites) )
    local suite_count="${#suites[@]}"
    echo "Installing all $suite_count suites..."
    for s in "${suites[@]}"; do
        echo "Installing [$s]"
        ./skema uninstall_suite "$s"
        ./skema install_suite "$s"
    done

    # This is to verify that the suites are installed
    local installed_suites=( $(./skema list_installed_suites) )
    local installed_suite_count="${#installed_suites[@]}"
    if [[ "$installed_suite_count" -ne "$suite_count" ]]; then
        err "Error while installing suites"
        exit 1
    fi
    return "$exit_status"
}

##################################################################
# Run all the installed skema suites
#
# Globals
#   None
# Arguments:
#   None
# Returns:
#   None
##################################################################
function run_tests {

    start_dbus

    cd "$SKEMA_BIN_DIR"

    # Retrieve the list of installed suites
    local installed_suites=( $(./skema list_installed_suites) )
    local installed_suite_count="${#installed_suite_count[@]}"
    local exit_status=0
    for s in "${installed_suites[@]}"; do
        # Check if the suite is exempt
        exists_in_array "$s" "${SKEMA_EXEMPT_SUITES[@]}"
        exit_status=$?
        if [[ "$exit_status" -eq 0 ]]; then
            err "Skipping suite : $s"
            continue
        fi

        echo "Running [$s]"
        ./skema run_suite "$s"
        exit_status=$?
        if [[ "$exit_status" -ne 0 ]]; then
            err "Error in suite: $s"
            exit 1
        fi
    done
    return "$exit_status"
}

##################################################################
# Main function
#
# Globals
#   INSTALL_DIR
# Arguments:
#   None
# Returns:
#   None
##################################################################
function main {

    if [ "$1" == "deps" ];  then
        install_deps
        exit_status=$?
    elif [ "$1" == "pydeps" ];  then
        install_python_deps
        exit_status=$?
    elif [ "$1" == "srcdeps" ];  then
        install_src_deps
        exit_status=$?
    elif [ "$1" == "debug" ]; then
        build_debug
        exit_status=$?
    elif [ "$1" == "release" ];  then
        build_release
        exit_status=$?
    elif [ "$1" == "conf" ];  then
        build_conformace
        exit_status=$?
    elif [ "$1" == "media" ];  then
        cd_to_working_dir
        echo "Downloading test media files to $INSTALL_DIR..."
        mkdir -p "$INSTALL_DIR" \
            && cd "$INSTALL_DIR" \
            && wget http://www.juanrubio.me/tizonia/tizonia-test-media.tgz \
            && tar zxvf tizonia-test-media.tgz &>/dev/null
        exit_status=$?
    elif [ "$1" == "config" ];  then
        copy_config_files
        exit_status=$?
    elif [ "$1" == "bldonly" ];  then
        echo "Build only..."
    elif [ "$1" == "tizonia" ]; then
        build_tizonia
        exit_status=$?
    elif [ "$1" == "skema" ];  then
        install_skema
        exit_status=$?
    elif [ "$1" == "tests" ];  then
        run_tests
        exit_status=$?
    else
        CMD=$(basename "$0")
        echo "Usage: $CMD <debug|release|conf|deps|media|config|skema|tests|bldonly> <working_dir> <install_dir>"
        exit 1
    fi

    if [ "$1" == "debug" ] || [ "$1" == "release" ] || [ "$1" == "conf" ] || [ "$1" == "bldonly" ] ; then
        cd_to_working_dir
        if [[ "$exit_status" -eq 0 ]] ; then
            make -s -j8 V=0
            exit_status=$?
        fi

        if [ ! "$1" == "bldonly" ] ; then
            if [[ "$exit_status" -eq 0 ]] ; then
                make -j8 install
                exit_status=$?
            fi
        fi
    fi

    cd "$CWD"

    exit "$exit_status"
}

main "$@"
